package app.jppfnetmorph;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import netmorph.model.NetmorphModel;
import netmorph.model.parts.BESInputModel;
import netmorph.model.parts.BESOutputModel;
import netmorph.model.parts.ElongInputModel;
import netmorph.model.parts.ElongOutputModel;

import model.ModelPart;
import netmorph.model.parts.TuftBEPart;
import netmorph.model.parts.BasalBEPart;
import netmorph.model.parts.NetmorphModelBESPart;
import netmorph.model.parts.NetmorphModelElongPart;
import netmorph.model.parts.ObliqueBEPart;

public class NetmorphConfig {

	public static interface Initializer {
		public void init(NetmorphModel model, BESInputModel bes, ElongInputModel elong);
	}
	
	BESInputModel besInputModel;
	BESOutputModel besOutputModel;
	
	ElongInputModel elongInputModel;
	ElongOutputModel elongOutputModel;
	
	NetmorphModel model;  
/*
	ModelPart basalBES;
	ModelPart apicalBES;
	ModelPart obliqueBES;
	*/
	int neuronPopulationSize = 10;
	
	public NetmorphConfig(Initializer init) {
		
		model = new NetmorphModel();
		
		besInputModel = new BESInputModel(model);
		besOutputModel = new BESOutputModel(model);
		
		elongInputModel = new ElongInputModel(model);
		elongOutputModel = new ElongOutputModel(model);
		
		if (init != null) init.init(model, besInputModel, elongInputModel);
		
		/*
		basalBES = new BasalBEPart(besInputModel, besOutputModel, model);
		apicalBES = new ApicalBEPart(besInputModel, besOutputModel, model);
		obliqueBES = new ObliqueBEPart(besInputModel, besOutputModel, model);
		*/
	}
	
	public String createConfig(double[] x, long seed, Class <? extends NetmorphModelBESPart> partClass) throws Exception 
	{
		return createConfig(x, seed, partClass, null);
	}
	
	public String createConfig(double[] x, long seed, Class <? extends NetmorphModelBESPart> partClass, Class <? extends NetmorphModelElongPart> elongClass) throws Exception
	{
		model.setParam("V.pyramidal", "" + neuronPopulationSize);		
		model.setParam("randomseed", ""+Math.abs(seed));
		model.setParam("warnings_on", "file");

		if (partClass != null) {
			Constructor<? extends NetmorphModelBESPart> partCons = partClass.getConstructor(BESInputModel.class, BESOutputModel.class, NetmorphModel.class);
			NetmorphModelBESPart part = partCons.newInstance(besInputModel, besOutputModel, model);
			
			part.x = x;
			part.setParameters();
		}
		if (elongClass != null) {
			Constructor<? extends NetmorphModelElongPart> elongCons = elongClass.getConstructor(ElongInputModel.class, ElongOutputModel.class, NetmorphModel.class);
			NetmorphModelElongPart part = elongCons.newInstance(elongInputModel, elongOutputModel, model);
			
			part.x = x;
			part.setParameters();
		}
		
		return model.createConfig();
	}

	protected void setNeuronPopulationSize(int neuronPopulationSize) {
		this.neuronPopulationSize = neuronPopulationSize;
	}
	

}
